//
//  OACellConfig.m
//  OASDK_Works
//
//  Created by ChenJie on 3/29/20.
//  Copyright © 2020 Mist. All rights reserved.
//

#import "OACellConfig.h"
#import "OABase.h"
#import "OALog.h"
#import "OACellProtocol.h"
#import "OADefaultCell.h"
#import "OACellConfig+ViewModelManager.h"
#import "OASectionConfig.h"

static NSInteger _cellIdSequence = 0;

@interface OACellConfig ()

@property (nonatomic, assign, class) NSInteger cellIdSequence;
@property (nonatomic, strong) NSMutableDictionary<id, OACellActionCallback> *actionPool;
@property (nonatomic, assign) CGFloat bottomSeparatorMarginTop;

@end

@implementation OACellConfig

#pragma mark - Lifecycle methods

- (instancetype)init {
    self = [super init];
    if (self) {
        self.cellSelectionStyle = UITableViewCellSelectionStyleNone;
    }
    return self;
}

- (instancetype)initWithType:(NSString *)cellType viewModel:(id)viewModel {
    self = [self init];
    if (self) {
        self.cellClass = NSClassFromString(cellType);
        NSString *cellType = NSStringFromClass(self.cellClass);
        self.cellViewModel = [OACellConfig cellViewModelWithCellType:cellType viewModelInfo:viewModel];
    }
    return self;
}

- (instancetype)initWithType:(NSString *)cellType staticHeight:(CGFloat)staticHeight viewModel:(id)viewModel{
    self = [self initWithType:cellType viewModel:viewModel];
    if (self) {
        self.staticHeight = staticHeight;
    }
    return self;
}

- (instancetype)initWithName:(NSString *)name cellType:(NSString *)cellType viewModel:(id)viewModel {
    self = [self initWithType:cellType viewModel:viewModel];
    if (self) {
        self.name = name;
    }
    return self;
}

- (instancetype)initWithName:(NSString *)name
                    cellType:(NSString *)cellType
                staticHeight:(CGFloat)staticHeight
                   viewModel:(id)viewModel {
    
    self = [self initWithName:name cellType:cellType viewModel:viewModel];
    if (self) {
        self.staticHeight = staticHeight;
    }
    return self;
}

+ (instancetype)cellWithType:(NSString *)cellType viewModel:(id)viewModel {
    return [[OACellConfig alloc] initWithType:cellType viewModel:viewModel];
}

+ (instancetype)cellWithType:(NSString *)cellType staticHeight:(CGFloat)staticHeight viewModel:(id)viewModel {
    return [[OACellConfig alloc] initWithType:cellType staticHeight:staticHeight viewModel:viewModel];
}

+ (instancetype)cellWithName:(NSString *)name cellType:(NSString *)cellType viewModel:(id)viewModel {
    return [[OACellConfig alloc] initWithName:name cellType:cellType viewModel:viewModel];
}

+ (instancetype)cellWithName:(NSString *)name
                    cellType:(NSString *)cellType
                staticHeight:(CGFloat)staticHeight
                   viewModel:(id)viewModel{
    
    return [[OACellConfig alloc] initWithName:name
                                     cellType:cellType
                                 staticHeight:staticHeight
                                    viewModel:viewModel];
}

#pragma mark - Public methods

/* add action */
- (void)setAction:(OACellActionCallback)action forEvent:(id)event {
    self.actionPool[event] = action;
}

/* update cell */
- (void)updateCell {
    [self updateCellWithAnimation:UITableViewRowAnimationNone];
}

- (void)updateCellWithAnimation:(UITableViewRowAnimation)animation {
    [self.sectionConfig updateCell:self withAnimation:animation];
}

#pragma mark - Delegate methods

/* UITableViewDataSource */
- (UITableViewCell *)cellForRowWithTableView:(UITableView *)tableView {
    NSString *cellIdentifier = NSStringFromClass(self.cellClass);
    UITableViewCell<OACellProtocol> *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        [tableView registerClass:self.cellClass forCellReuseIdentifier:cellIdentifier];
        cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    }
    
    cell.viewModel = self.cellViewModel;
    cell.selectionStyle = self.cellSelectionStyle;
    
    // todo: define separator in cellConfig
    
    // top separator
    if (!OAIsEmptyLineInset(self.topSeparator)) {
        
        // bounds
        CGRect bounds = cell.contentView.bounds;
        bounds.origin.y = - OALineOffsetHeight(self.topSeparator);
        cell.contentView.bounds = bounds;
        
        //
        cell.oa_topSeparator.frame = [self separatorFrameWithTopMargin:0
                                                             cellWidth:tableView.oa_width
                                                             lineInset:self.topSeparator];
        cell.oa_topSeparator.backgroundColor = self.topSeparatorColor;
    }
    
    // bottom separator
    if (!OAIsEmptyLineInset(self.bottomSeparator)) {
        cell.oa_bottomSeparator.frame = [self separatorFrameWithTopMargin:self.bottomSeparatorMarginTop
                                                                cellWidth:tableView.oa_width
                                                                lineInset:self.bottomSeparator];
        cell.oa_bottomSeparator.backgroundColor = self.bottomSeparatorColor;
    }
    
//    cell.backgroundColor = OARandomColor();
    
    // todo: cell_layout
//    cell.oa_layout = self.cellLayout;
    
    return cell;
}

/* UITableViewDelegate */
- (CGFloat)heightForRowWithCellWidth:(CGFloat)cellWidth {
    
    if (cellWidth == 0) {
        return 0;
    }
    
    // static height
    if (self.staticHeight) {
        if ([self.cellClass respondsToSelector:@selector(oa_layoutWithCellSize:viewModel:)]) {
            [self.cellClass oa_layoutWithCellSize:CGSizeMake(cellWidth, self.staticHeight) viewModel:self.cellViewModel];
        }
        return self.staticHeight;
    }
    
    // calculate height
    CGFloat cellHeight = 0;
    if ([self.cellClass respondsToSelector:@selector(oa_heightWithWidth:viewModel:)]) {
        cellHeight = [self.cellClass oa_heightWithWidth:cellWidth viewModel:self.cellViewModel];
    }
    
    if (!OAIsEmptyLineInset(self.topSeparator)) {
        cellHeight += OALineOffsetHeight(self.topSeparator);
    }
    
    if (!OAIsEmptyLineInset(self.bottomSeparator)) {
        self.bottomSeparatorMarginTop = cellHeight;
        cellHeight += OALineOffsetHeight(self.bottomSeparator);
    }
    
    return cellHeight;
}

- (void)didSelectRow {
    !self.cellDidSelect ?: self.cellDidSelect(self);
}

#pragma mark - Private methods

- (void)executeActionCallbackWithEvent:(id)event {
    if (!event) {
        return;
    }
    
    OACellActionCallback cellAction = self.actionPool[event];
    !cellAction ?: cellAction(self);
}

- (CGRect)separatorFrameWithTopMargin:(CGFloat)topMargin
                            cellWidth:(CGFloat)cellWidth
                            lineInset:(OALineInset)lineInset {
    
    CGFloat top = topMargin + lineInset.top;
    CGFloat width = lineInset.width ?: cellWidth - lineInset.left - lineInset.right;
    return CGRectMake(lineInset.left, top, width, lineInset.height);
}

#pragma mark - Delegate methods



#pragma mark - Setter

+ (void)setCellIdSequence:(NSInteger)cellIdSequence {
    _cellIdSequence = cellIdSequence;
}

- (void)setCellViewModel:(id<OACellViewModelProtocol>)cellViewModel {
    _cellViewModel = cellViewModel;
    
    //
    __weak typeof(self) weakSelf = self;
    cellViewModel.oa_executeActionWithEvent = ^(id event) {
        [weakSelf executeActionCallbackWithEvent:event];
    };
}

#pragma mark - Getter

+ (NSInteger)cellIdSequence {
    return _cellIdSequence;
}

- (NSString *)name {
    if (!_name) {
        _name = [NSString stringWithFormat:@"cell_%ld", (long)OACellConfig.cellIdSequence++];
    }
    return _name;
}

- (Class)cellClass {
    if (!_cellClass) {
        Class cellClass = OADefaultCell.class;
        _cellClass = cellClass;
    }
    return _cellClass;
}

- (NSIndexPath *)indexPath {
    if (!self.indexPathOfCell) {
        return nil;
    }
    return self.indexPathOfCell(self);
}

- (OASectionConfig *)sectionConfig {
    if (!self.sectionOfCell) {
        return nil;
    }
    return self.sectionOfCell();
}

- (NSMutableDictionary *)actionPool {
    if (!_actionPool) {
        _actionPool = [NSMutableDictionary dictionary];
    }
    return _actionPool;
}

#pragma mark - Memory management methods

- (void)dealloc {
    OALogFunction
}

@end
